#include "esp_eap_client.h"
#include "esp_wifi.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "Drivers/wifi_drv.h"
#include "Drivers/nvs_drv.h"
#include "esp_timer.h"
#include "App/uart_data.h"

#define TAG   "wifi_drv"
modelRunningStatus_t running = 
{
    .IsConnected = false,
    .IsSmartConfig = false,
    .IsConnectServer = false,
};
EventGroupHandle_t WifiEventGroup = NULL;
static char g_ssid[SSID_MAX_LEN];
static char g_password[PASS_MAX_LEN];

static uint8_t g_ReConnectCount = 0;
static void ReconnectToWifiTask(void *param);

/**
 * @brief WiFi事件处理回调函数
 *
 * 处理WiFi连接过程中的各种事件:
 * - WIFI_EVENT_STA_START: WiFi启动后开始连接
 * - WIFI_EVENT_STA_DISCONNECTED: WiFi断开连接后进行重连
 * - IP_EVENT_STA_GOT_IP: 获取IP后设置连接状态
 *
 * @param arg 事件处理函数的参数
 * @param event_base 事件基类型
 * @param event_id 事件ID
 * @param event_data 事件数据
 */
static void event_handler(void *arg, esp_event_base_t event_base,
                          int32_t event_id, void *event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
    {
        ESP_LOGI(TAG, "WIFI_START");
        esp_wifi_connect();
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        running.IsConnected = false;
        g_ReConnectCount++;
        ESP_LOGI(TAG, "WIFI_RESTART");
        if (g_ReConnectCount >= RECONNECT_INTERVAL)
        {
            g_ReConnectCount = 0;
            xTaskCreate(ReconnectToWifiTask, "ReconnectToWifiTask", 2048, NULL, 2, NULL);
        }
        else    esp_wifi_connect();      
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        ESP_LOGI(TAG, "IP_STA_GOT_IP");
        g_ReConnectCount = 0;
        running.IsConnected = true;
        ResponseWifiStatus(NORMAL_RUNNING);
        xEventGroupSetBits(WifiEventGroup, WIFI_CONNECTED_BIT);
    }
}

/**
 * @brief 连接到 WiFi 网络
 *
 * 该函数负责初始化并配置 ESP32 的 WiFi 功能，包括:
 * - 创建 WiFi 事件组
 * - 初始化默认事件循环
 * - 创建和配置 WiFi station 接口
 * - 注册 WiFi 和 IP 事件处理程序
 * - 从 NVS 中读取已保存的 WiFi 凭据
 * - 如果没有保存的凭据则使用默认配置
 * - 启动 WiFi 连接
 *
 * @note 函数使用全局变量 g_ssid 和 g_password 存储 WiFi 凭据
 * @note 如果 NVS 中没有保存的凭据,将使用 DEFAULT_SSID 和 DEFAULT_PSWD 进行连接
 */
void ConnectToWifi(void)
{
    WifiEventGroup = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *sta_netif =  esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));

    read_nvs_space(NVS_WIFI_NAMESPACE, NVS_WIFI_SSID_KEY,g_ssid, sizeof(g_ssid));
    read_nvs_space(NVS_WIFI_NAMESPACE, NVS_WIFI_PASS_KEY,g_password, sizeof(g_password)); 
    ESP_LOGI(TAG, "ssid:%s, password:%s", g_ssid, g_password);

    if (g_ssid[0] != 0)   
       ESP_ERROR_CHECK(esp_wifi_start());   
    else
    {
        wifi_config_t wifi_config =
        {
            .sta =
            {
                .ssid = DEFAULT_SSID,
                .password = DEFAULT_PSWD,
                 .threshold.authmode = WIFI_AUTH_WPA2_PSK,
                .pmf_cfg =
                {
                    .capable = true,
                    .required = false
                },
            },
        };
        ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
        ESP_ERROR_CHECK(esp_wifi_start()); 
    }
}

/**
 * @brief WiFi重连任务函数
 *
 * 该函数作为任务运行,在WiFi断开连接后尝试重新连接。主要功能:
 * - 发送WiFi断开状态通知(最多RESPONSE_COUNT次)
 * - 等待RECONNECT_TIMEOUT秒
 * - 如果在等待期间SmartConfig被触发则退出
 * - 超时后尝试重新连接WiFi
 *
 * @param param 任务参数(未使用)
 * @return void
 */
static void ReconnectToWifiTask(void *param)
{
    int64_t now = esp_timer_get_time() / 1000000LL;
    static uint8_t RespCount = 0;
    ++RespCount;
    if(RespCount <= RESPONSE_COUNT)
        ResponseWifiStatus(WIFI_DISCONNECTED);

    while (esp_timer_get_time() / 1000000LL - now < RECONNECT_TIMEOUT)
    {
        if (running.IsSmartConfig)
        {
            ESP_LOGI(TAG, "reconnect exit");
            vTaskDelete(NULL);
        }        
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
    esp_wifi_connect();
    vTaskDelete(NULL);
}
